#define MAX_EXTRA_COUNT 256
typedef struct {
uint16_t keysym2keycode[MAX_NORMAL_KEYCODE];
+ int keysym2numlock[MAX_NORMAL_KEYCODE];
struct {
int keysym;
+ int numlock;
uint16_t keycode;
} keysym2keycode_extra[MAX_EXTRA_COUNT];
int extra_count;
char file_name[1024];
char line[1024];
int len;
+ int *keycode2numlock;
+ int i;
snprintf(file_name, sizeof(file_name),
"%s/keymaps/%s", bios_dir, language);
"Could not read keymap file: '%s'\n", file_name);
return 0;
}
+
+ /* Allocate a temporary map tracking which keycodes change when numlock is
+ set. Keycodes are 16 bit, so 65536 is safe. */
+ keycode2numlock = malloc(65536 * sizeof(int));
+ if (!keycode2numlock) {
+ perror("Could not read keymap file");
+ return 0;
+ }
+
for(;;) {
if (fgets(line, 1024, f) == NULL)
break;
if (keysym == 0) {
// fprintf(stderr, "Warning: unknown keysym %s\n", line);
} else {
- const char *rest = end_of_keysym + 1;
- int keycode = strtol(rest, NULL, 0);
+ char *rest = end_of_keysym + 1;
+ int keycode = strtol(rest, &rest, 0);
+ int numlock = (rest != NULL &&
+ strstr(rest, "numlock") != NULL);
+
+ keycode2numlock[keycode] = numlock;
+
/* if(keycode&0x80)
keycode=(keycode<<8)^0x80e0; */
if (keysym < MAX_NORMAL_KEYCODE) {
//fprintf(stderr,"Setting keysym %s (%d) to %d\n",line,keysym,keycode);
k->keysym2keycode[keysym] = keycode;
+ k->keysym2numlock[keysym] = numlock;
} else {
if (k->extra_count >= MAX_EXTRA_COUNT) {
fprintf(stderr,
keysym = keysym;
k->keysym2keycode_extra[k->extra_count].
keycode = keycode;
+ k->keysym2keycode_extra[k->extra_count].
+ numlock = numlock;
k->extra_count++;
}
}
}
}
fclose(f);
+
+ for (int i = 0; i < MAX_NORMAL_KEYCODE; i++) {
+ if (k->keysym2numlock[i] != 1) {
+ k->keysym2numlock[i] = -keycode2numlock[k->keysym2keycode[i]];
+ }
+ }
+
+ for (int i = 0; i < k->extra_count; i++) {
+ if (k->keysym2keycode_extra[i].numlock != 1) {
+ k->keysym2keycode_extra[i].numlock =
+ -keycode2numlock[k->keysym2keycode_extra[i].keycode];
+ }
+ }
+
+ free(keycode2numlock);
+
return k;
}
}
return 0;
}
+
+/**
+ * Returns 1 if the given keysym requires numlock to be pressed, -1 if it
+ * requires it to be cleared, and 0 otherwise.
+ */
+static int keysym2numlock(void *kbd_layout, int keysym)
+{
+ kbd_layout_t *k = kbd_layout;
+ if (keysym < MAX_NORMAL_KEYCODE) {
+ return k->keysym2numlock[keysym];
+ } else {
+ int i;
+#ifdef XK_ISO_Left_Tab
+ if (keysym == XK_ISO_Left_Tab)
+ keysym = XK_Tab;
+#endif
+ for (i = 0; i < k->extra_count; i++)
+ if (k->keysym2keycode_extra[i].keysym == keysym)
+ return k->keysym2keycode_extra[i].numlock;
+ }
+ return 0;
+}
int ctl_keys; /* Ctrl+Alt starts calibration */
int shift_keys; /* Shift / CapsLock keys */
+ int numlock;
};
#define DIRTY_PIXEL_BITS 64
}
}
+static void press_key(VncState *vs, int keycode)
+{
+ kbd_put_keycode(keysym2scancode(vs->kbd_layout, keycode) & 0x7f);
+ kbd_put_keycode(keysym2scancode(vs->kbd_layout, keycode) | 0x80);
+}
+
static void do_key_event(VncState *vs, int down, uint32_t sym)
{
sym &= 0xFFFF;
if (is_graphic_console()) {
int keycode;
+ int numlock;
keycode = keysym2scancode(vs->kbd_layout, sym);
+ numlock = keysym2numlock(vs->kbd_layout, sym);
+
+ /* If the numlock state needs to change then simulate an additional
+ keypress before sending this one. This will happen if the user
+ toggles numlock away from the VNC window.
+ */
+ if (numlock == 1) {
+ if (!vs->numlock) {
+ vs->numlock = 1;
+ press_key(vs, XK_Num_Lock);
+ }
+ }
+ else if (numlock == -1) {
+ if (vs->numlock) {
+ vs->numlock = 0;
+ press_key(vs, XK_Num_Lock);
+ }
+ }
+
if (keycode & 0x80)
kbd_put_keycode(0xe0);
if (down)
vs->shift_keys ^= 2;
break;
+ case XK_Num_Lock:
+ vs->numlock = !vs->numlock;
+ break;
+
case XK_1 ... XK_9:
if ((vs->ctl_keys & 3) != 3)
break;
vs->lsock = -1;
vs->csock = -1;
vs->depth = 4;
+ vs->numlock = 0;
vs->ds = ds;
{"Home", 0xff50}, /* XK_Home */
{"End", 0xff57}, /* XK_End */
{"Scroll_Lock", 0xff14}, /* XK_Scroll_Lock */
+{"KP_Home", 0xff95},
+{"KP_Left", 0xff96},
+{"KP_Up", 0xff97},
+{"KP_Right", 0xff98},
+{"KP_Down", 0xff99},
+{"KP_Prior", 0xff9a},
+{"KP_Page_Up", 0xff9a},
+{"KP_Next", 0xff9b},
+{"KP_Page_Down", 0xff9b},
+{"KP_End", 0xff9c},
+{"KP_Begin", 0xff9d},
+{"KP_Insert", 0xff9e},
+{"KP_Delete", 0xff9f},
{"F1", 0xffbe}, /* XK_F1 */
{"F2", 0xffbf}, /* XK_F2 */
{"F3", 0xffc0}, /* XK_F3 */
{"KP_8", 0xffb8}, /* XK_KP_8 */
{"KP_9", 0xffb9}, /* XK_KP_9 */
{"KP_Add", 0xffab}, /* XK_KP_Add */
+{"KP_Separator", 0xffac},/* XK_KP_Separator */
{"KP_Decimal", 0xffae}, /* XK_KP_Decimal */
{"KP_Divide", 0xffaf}, /* XK_KP_Divide */
{"KP_Enter", 0xff8d}, /* XK_KP_Enter */